/**
 * 
 */
/**
 * @author dgsai
 *
 */
package cn.edu.dgut.sw.security.oauth2.weixin.config;

import javax.servlet.Filter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import cn.edu.dgut.sw.security.oauth2.weixin.WeiXinOAuth2RedirectStrategy;
import cn.edu.dgut.sw.security.oauth2.weixin.WeiXinOAuth2RestTemplate;
import cn.edu.dgut.sw.security.oauth2.weixin.WeiXinOAuth2UserInfoTokenServices;

public class MultiHttpSecurityConfig {

	// 微信网页授权登录
	@Configuration
	@EnableOAuth2Client // 开启Oauth2,必需定义在这里
	public static class WeiXinLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

		@Autowired
		OAuth2ClientContext oauth2ClientContext;

		@Override
		public void configure(WebSecurity web) throws Exception {
			web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
		}

		@Override
		protected void configure(HttpSecurity http) throws Exception {
			// match"/**"
			http.antMatcher("/**")
					.authorizeRequests().antMatchers("/", "/login**", "/webjars/**").permitAll().anyRequest().authenticated().and()
					.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and()
					.logout()
						.logoutSuccessUrl("/").permitAll().and()
					.csrf()
						.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
					.addFilterBefore(weixinSSOFilter(), BasicAuthenticationFilter.class);
		}

		// 微信登录拦截器filter
		private Filter weixinSSOFilter() {
			OAuth2ClientAuthenticationProcessingFilter weixinSSOFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/weixin");
			WeiXinOAuth2RestTemplate weixinOAuth2RestTemplate = new WeiXinOAuth2RestTemplate(weixin(), oauth2ClientContext);
			weixinSSOFilter.setRestTemplate(weixinOAuth2RestTemplate);
			WeiXinOAuth2UserInfoTokenServices tokenServices = new WeiXinOAuth2UserInfoTokenServices(weixinResource().getUserInfoUri(), weixin().getClientId());
			tokenServices.setRestTemplate(weixinOAuth2RestTemplate);
			weixinSSOFilter.setTokenServices(tokenServices);
			return weixinSSOFilter;
		}

		// 读取配置文件application.yml
		@Bean
		@ConfigurationProperties("weixin.client")
		public AuthorizationCodeResourceDetails weixin() {
			return new AuthorizationCodeResourceDetails();
		}

		// 读取配置文件application.yml
		@Bean
		@ConfigurationProperties("weixin.resource")
		public ResourceServerProperties weixinResource() {
			return new ResourceServerProperties();
		}

		// 必需加这个Bean
		// 因为spring boot抛弃了xml配置，所以在注册servlet filter时，要用其它方法。
		// 在spring boot中，FilterRegistrationBean用于注册servlet filter。可定义多个，用于注册多个filter。
		// 先定义filter的Bean,再定义FilterRegistrationBean，从构造函数注入fitler,完成注册。
		// 此类提供setOrder方法，可以为filter设置排序值，让spring在注册web filter之前排序后依次注册，值越小越先执行。
		@Bean
		public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
			FilterRegistrationBean registration = new FilterRegistrationBean();
			// 设置自定义的微信网页授权的重定向策略对象
			filter.setRedirectStrategy(new WeiXinOAuth2RedirectStrategy());
			registration.setFilter(filter);
			registration.setOrder(-100);
			return registration;
		}
	}
}